package com.mvc.frame.sys;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;

/**
 * 切面统一管理日志：<br>
 * 1.引入依赖：<artifactId>aop</artifactId><br>
 * 2.需要使用CGLIB来实现AOP的时候，需要配置spring.aop.proxy-target-class=true，不然默认使用的是标准Java的实现<br>
 * 实现AOP的切面主要有以下几个要素：<br>
 * 使用@Aspect注解将一个java类定义为切面类<br>
 * 使用@Pointcut定义一个切入点，可以是一个规则表达式，比如下例中某个package下的所有函数，也可以是一个注解等<br>
 * 根据需要在切入点不同位置的切入内容<br>
 * 使用@Before在切入点开始处切入内容<br>
 * 使用@After在切入点结尾处切入内容<br>
 * 使用@AfterReturning在切入点return内容之后切入内容（可以用来对处理返回值做一些加工处理）<br>
 * 使用@Around在切入点前后切入内容，并自己控制何时执行切入点自身的内容<br>
 * 使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑<br>
 * 
 * @author Zhang.Yan
 *
 */

public class LogAspect
{
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	private ThreadLocal<Map<String, Object>> threadLocal=new ThreadLocal<Map<String, Object>>();
	
	
	public void doBefore(JoinPoint joinPoint) throws Throwable
	{
		String uuid=Utils.getUUID();
		long stime=new Date().getTime();
		Map<String, Object> map=new HashMap<>();
		map.put("uuid", uuid);
		map.put("stime", stime);
		threadLocal.set(map);
		// 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Map<String, Object> reqInfo=new HashMap<>();
        reqInfo.put("url", request.getRequestURI());
        reqInfo.put("method", request.getMethod());
        Signature sign=joinPoint.getSignature();
        reqInfo.put("class", sign.getDeclaringTypeName()+"."+sign.getName());
        reqInfo.put("args", Arrays.toString(joinPoint.getArgs()));
        reqInfo.put("addr", request.getRemoteAddr());
        Map<String, Object> requestm=new HashMap<>();
        requestm.put("stime", stime);
        requestm.put("uuid", uuid);
        requestm.put("request", reqInfo);
        logger.info("请求信息:"+JSON.toJSONString(requestm));
	}
	
	
	public void doAfterReturn(Object res) throws Throwable
	{
		Map<String, Object> map=threadLocal.get();
		String uuid=(String) map.get("uuid");
		long stime=(long) map.get("stime");
		long etime=new Date().getTime();
		long time=etime-stime;
		Map<String, Object> result=new HashMap<>();
		result.put("etime", etime);
		result.put("uuid", uuid);
		result.put("tdiff", time);
		result.put("response", res);
		logger.info("响应信息:"+JSON.toJSONString(result));
		threadLocal.remove();
	}
}
